/*local function aimassistprintoutbrah(var)
	if var == 0 then
		CONS_Printf(server, "Are you sure you want to disable Aim Assist entirely? Its recommended you set this variable to at least 1 if there are any controller players present.")
		CONS_Printf(server, "(Unless you really just want to be that competitive.)")
	elseif var > 5 then
		CONS_Printf(server, "Are you sure you want to enable Aim Assist values above 5? The current value is " .. var .. ". Its recommended you set this variable to 5 or under for a fun experience.")
	end
	if not var then
		CONS_Printf(server, "Limits the max value players are allowed to set their aim assist to.")
	end
end*/

freeslot("sfx_locko1", "sfx_locko2", "sfx_autof1", "sfx_autof2")

RFW.maxaimassist = CV_RegisterVar({
	name = "aimassistsize",
	defaultvalue = 1,
	PossibleValue = {MIN = 0, MAX = 3},
	flags = CV_NETVAR
})

RFW.vertassist = CV_RegisterVar({
	name = "aimassistaxis",
	defaultvalue = "Both",
	PossibleValue = {Both = 0, Vertical = 1, Horizontal = 2},
	flags = CV_NETVAR
})

RFW.assiststyle = CV_RegisterVar({
	name = "aimassiststyle",
	defaultvalue = "Halo",
	PossibleValue = {Halo = 0, Lockon = 1},
	flags = CV_NETVAR
})

/*RFW.autofire = CV_RegisterVar({
	name = "autofire",
	defaultvalue = "Off",
	PossibleValue = CV_OnOff,
	flags = 0
})*/

RFW.assistff = CV_RegisterVar({
	name = "allowassistfriendlyfire", //for if your friends are dick/doing srb2hood coop and people are shooting each other
	defaultvalue = "False",
	PossibleValue = CV_TrueFalse,
	flags = 0
})

COM_AddCommand("aimassist", function (p, arg)
	if arg == "0" or string.lower(arg or 0) == "false" then
		CONS_Printf(p, "Aim Assist has been disabled.")
		p.aimassist = 0
	elseif arg == "1" or string.lower(arg or 0) == "true" or string.lower(arg or 0) == "on" or string.lower(arg or 0) == "both" then
		CONS_Printf(p, "Aim Assist has been enabled, Aiming on both axises.")
		p.aimassist = 1
	elseif arg == "3" or string.lower(arg or 0) == "horizontal" or string.lower(arg or 0) == "horiz" then
		CONS_Printf(p, "Aim Assist has been enabled, Aiming on horizontal axis.")
		p.aimassist = 3
	elseif arg == "2" or string.lower(arg or 0) == "vertical" or string.lower(arg or 0) == "vert" then
		CONS_Printf(p, "Aim Assist has been enabled, Aiming on vertical axis.")
		p.aimassist = 2
	else
		CONS_Printf(p, "Controls the axis of Aiming Assistance or disables it.")
		//CONS_Printf(p, "Allowed axis by the server is " .. RFW.vertassist.value .. ".")
	end
end)

COM_AddCommand("aimassist2", function (p, arg)
	if arg == "0" or string.lower(arg or 0) == "false" then
		print("Aim Assist has been disabled.")
		p.aimassist = 0
	elseif arg == "1" or string.lower(arg or 0) == "true" or string.lower(arg or 0) == "on" or string.lower(arg or 0) == "both" then
		print("Aim Assist has been enabled, Aiming on both axises.")
		p.aimassist = 1
	elseif arg == "3" or string.lower(arg or 0) == "horizontal" or string.lower(arg or 0) == "horiz" then
		print("Aim Assist has been enabled, Aiming on horizontal axis.")
		p.aimassist = 3
	elseif arg == "2" or string.lower(arg or 0) == "vertical" or string.lower(arg or 0) == "vert" then
		print("Aim Assist has been enabled, Aiming on vertical axis.")
		p.aimassist = 2
	else
		print("Controls the axis of Aiming Assistance or disables it.")
		//print("Allowed axis by the server is " .. RFW.vertassist.value .. ".")
	end
end, COM_SPLITSCREEN)

COM_AddCommand("autofire", function (p, arg)
	if arg == "0" or string.lower(arg or 0) == "false" or string.lower(arg or 0) == "off" then
		CONS_Printf(p, "Autofire has been disabled.")
		p.autofire = 0
	elseif arg == "1" or string.lower(arg or 0) == "true" or string.lower(arg or 0) == "on" then
		CONS_Printf(p, "Autofire has been enabled.")
		p.autofire = 1
	else
		CONS_Printf(p, "Automatically fires your weapon when aiming at enemies. Good for mobile players.")
	end
end)

COM_AddCommand("autofire2", function (p, arg)
	if arg == "0" or string.lower(arg or 0) == "false" or string.lower(arg or 0) == "off" then
		print("Autofire has been disabled.")
		p.autofire = 0
	elseif arg == "1" or string.lower(arg or 0) == "true" or string.lower(arg or 0) == "on" then
		print("Autofire has been enabled.")
		p.autofire = 1
	else
		print("Automatically fires your weapon when aiming at enemies. Good for mobile players.")
	end
end, COM_SPLITSCREEN)

/*COM_AddCommand("aimassiststyle", function (p, arg)
	if arg == nil then
		CONS_Printf(p, "Controls how Aim Assist works.")
		CONS_Printf(p, "(0) Lock-on, Works like traditional Aim Assist and attempts to move your camera towards valid targets.")
		CONS_Printf(p, "(1) Bullet Magnetism, Similar to how it works in games such as Halo. Camera remains unaffected but gun fire will veer towards valid targets.")
	elseif arg == "1" or arg == "magnet" or arg == "magnetism" or arg == "bullet" or arg == "bulletmagnetism" then
		CONS_Printf(p, "Aim Assist style has been set to bullet magnetism. Hitscan weapons will be drawn towards valid targets.")
		p.bulletmagnetism = 1
	elseif arg == "0" or arg == "camera" or arg == "lockon" or arg == "lock-on" or arg == "aim" or arg == "aimassist" then
		CONS_Printf(p, "Aim Assist style has been set to lock-on. Your camera will attempt to lock-on valid targets in front of you.")
		p.bulletmagnetism = 0
	else
		CONS_Printf(p, "Controls how Aim Assist works.")
		CONS_Printf(p, "(0) Lock-on, Works like traditional Aim Assist and attempts to move your camera towards valid targets.")
		CONS_Printf(p, "(1) Bullet Magnetism, Similar to how it works in games such as Halo. Camera remains unaffected but gun fire will veer towards valid targets.")
	end
end)

COM_AddCommand("aimassiststyle2", function (p, arg)
	if arg == nil then
		CONS_Printf(p, "Controls how Aim Assist works.")
		CONS_Printf(p, "(0) Lock-on, Works like traditional Aim Assist and attempts to move your camera towards valid targets.")
		CONS_Printf(p, "(1) Bullet Magnetism, Similar to how it works in games such as Halo. Camera remains unaffected but gun fire will veer towards valid targets.")
	elseif arg == "1" or arg == "magnet" or arg == "magnetism" or arg == "bullet" or arg == "bulletmagnetism" then
		CONS_Printf(p, "Aim Assist style has been set to bullet magnetism. Hitscan weapons will be drawn towards valid targets.")
		p.bulletmagnetism = 1
	elseif arg == "0" or arg == "camera" or arg == "lockon" or arg == "lock-on" or arg == "aim" or arg == "aimassist" then
		CONS_Printf(p, "Aim Assist style has been set to lock-on. Your camera will attempt to lock-on valid targets in front of you.")
		p.bulletmagnetism = 0
	else
		CONS_Printf(p, "Controls how Aim Assist works.")
		CONS_Printf(p, "(0) Lock-on, Works like traditional Aim Assist and attempts to move your camera towards valid targets.")
		CONS_Printf(p, "(1) Bullet Magnetism, Similar to how it works in games such as Halo. Camera remains unaffected but gun fire will veer towards valid targets.")
	end
end, COM_SPLITSCREEN)*/

addHook("PlayerThink", function(p)
	if p.aimassist then //run this if we're spec anyways lmfao
		if RFW.maxaimassist.value == 0 and p.aimassist ~= 0 and RFW.assiststyle.value == 1 then
			p.aimassist = 0
		elseif RFW.vertassist == 1 and p.aimassist ~= 2 and RFW.assiststyle.value == 1  then
			p.aimassist = 2
		elseif RFW.vertassist == 2 and p.aimassist ~= 3 and RFW.assiststyle.value == 1  then
			p.aimassist = 3
		elseif RFW.assiststyle.value == 0 and p.aimassist ~= 1 then
			p.aimassist = 1
		end
	end
	/*if p.bulletmagnetism == nil then
		p.bulletmagnetism = 0
	end*/
	if p.bot then
		p.aimassist = 0
		p.bulletmagnetism = 0
	end
	/*if p.bot then
		p.aimassist = 5
	end*/
	/*if p.aimassist == nil then
		p.aimassist = 0
	end
	if not p.aimassist return end
	if not next(P_AngleRaycast{x = p.mo.x, y = p.mo.y, z = p.mo.z+(24*FU), ang = p.mo.angle, zang = p.aiming, distance = 4096 * FU, steps = 256, tclip = true, lclip = true, ignore = p.mo}) then
		for i = -5, 5 do
			if next(P_AngleRaycast{x = p.mo.x, y = p.mo.y, z = p.mo.z+(24*FU), ang = p.mo.angle+ANG1*i, zang = p.aiming, distance = 4096 * FU, steps = 256, tclip = true, lclip = true, ignore = p.mo}) ~= nil then
				if i < 0 then
					p.mo.angle = $ - ANG1
				else
					p.mo.angle = $ + ANG1
				end
				break
			end
		end
		for i = -5, 5 do
			if next(P_AngleRaycast{x = p.mo.x, y = p.mo.y, z = p.mo.z+(24*FU), ang = p.mo.angle, zang = p.aiming+ANG1*i, distance = 4096 * FU, steps = 256, tclip = true, lclip = true, ignore = p.mo}) ~= nil then
				if i < 0 then
					p.aiming = $ - ANG1
				else
					p.aiming = $ + ANG1
				end
				break
			end
		end
	end*/
end)

//autoaim test

addHook("PlayerThink", function(p)
	if p.aimassist ~= nil then return end //run this if we're spec anyways
	//controller movement, autoset aimassist to on unless it was manually turned off/auto turned off by keyboard input
	if abs(p.cmd.forwardmove) == 35 and abs(p.cmd.sidemove) == 35 then
		p.aimassist = 0
		CONS_Printf(p, "Keyboard detected, Aim Assist was automatically disabled. Feel free to enable and change the strength using the 'aimassist' command.")
		return
	end
	if p.cmd.forwardmove > -50 and p.cmd.forwardmove ~= 0 and p.cmd.forwardmove < 50 then //analogue movement detected, likely controller player
		p.aimassist = 3
		CONS_Printf(p, "Controller detected, Aim Assist was automatically enabled and set to a strength of 3. Feel free to change the strength or disable it using the 'aimassist' command.")
		return
	end
	if p.cmd.sidemove > -50 and p.cmd.sidemove ~= 0 and p.cmd.sidemove < 50 then //"rdude should't you check mouse to account for keyboard only players/controller+mouse players?" shut up i dont care lmao toggle it yourself fatass
		p.aimassist = 3
		CONS_Printf(p, "Controller detected, Aim Assist was automatically enabled and set to a strength of 3. Feel free to change the strength or disable it using the 'aimassist' command.")
		return
	end
	//keyboard movement, autoset aimassist to off unless it was manually turned on/auto turned on by controller input
	if p.cmd.forwardmove == 50 or p.cmd.forwardmove == -50 then //digital movement detected (instant transition to max movement), likely keyboard player
		p.aimassist = 0
		CONS_Printf(p, "Keyboard detected, Aim Assist was automatically disabled. Feel free to enable and change the strength using the 'aimassist' command.")
		return
	end
	if p.cmd.sidemove == 50 or p.cmd.sidemove == -50 then
		p.aimassist = 0
		CONS_Printf(p, "Keyboard detected, Aim Assist was automatically disabled. Feel free to enable and change the strength using the 'aimassist' command.")
		return
	end
end)

/*addHook("PlayerThink", function(p)
	if not (p and p.mo) then return end //gotta start doing this more, don't run code if we're a spectator
	if p.aimassist == nil or p.aimassist == 0 then return end
	/*local target = P_AngleRaycast{x = p.mo.x, y = p.mo.y, z = p.mo.z+(p.mo.height*3/4), ang = p.mo.angle, zang = p.aiming, distance = 2048 * FU, steps = 64, tclip = true, lclip = true, ignore = p.mo}
	if not next(target) then
		
		return
	end
	if searchBlockmap("objects", function(ref, object)//lets recode ambush checks! horray!
		//if not (object.flags & MF_SHOOTABLE) then return nil end
		if object.type ~= MT_PLAYER then return nil end //prioritize players
		if CanPlayerHurtPlayerTeam(ref.player, object.player, 1) == false then return nil end //we cant hurt them or they're friendly with us, don't bother lmfao
		/*local oangle = ref.angle
		local dangle = R_PointToAngle2(object.x, object.y, ref.x, ref.y)
		local angle = dangle - oangle
		if (angle > ANGLE_180) then //idk why we do this lol
			angle = InvAngle($)
		end//FUCK THIS SHIT GRAH
		if 
			ref.lockontarget = object
			return true
		end
	end, p.mo, p.mo.x - 1024*FU, p.mo.x + 1024*FU, p.mo.y - 1024*FU, p.mo.y + 1024*FU) == false then return end //we have a target, stop here
	p.mo.lockontarget = nil
end)*/ 

/*addHook("PlayerThink", function(p)
	if not (p and p.mo) then return end //gotta start doing this more, don't run code if we're a spectator
	//or p.bulletmagnetism ~= 0 */
	/*if p.aimassist == nil or p.aimassist == 0 then //if aim assist is disabled or we're using bullet magnetism instead then don't try to lock on
		if p.mo.lockontarget then //if we had a target then forget them
			p.mo.lockontarget = nil
		end
		return
	end*/
/*	if p.mo.aimassistdelay == nil then 
		p.mo.aimassistdelay = 0
	end
	local targetlist
	if p.aimassist > 0 then
		targetlist = P_MagnetizedXYRaycast{x = p.mo.x, y = p.mo.y, ang = p.mo.angle, distance = 2048*FU, steps = 128, tclip = false, lclip = true, size = RFW.maxaimassist.value, ignore = p.mo}
	end
	if not next(targetlist) then
		p.mo.lockontarget = nil 
		p.mo.aimassistdelay = max($-1, 0)
		return
	end
	p.mo.lockontarget = nil
	for i = 1, #targetlist do
		local target = targetlist[i][3]
		local angletotarget = R_PointToAngle2(0, p.mo.z+p.mo.height/2, R_PointToDist2(p.mo.x, p.mo.y, target.x, target.y), target.z+target.height/2)
		if abs(p.aiming-angletotarget) > ANG30 then continue end //dont cut from extreme angles
		if not next(P_MagnetizedAngleRaycast{x = p.mo.x, y = p.mo.y, z = p.mo.z + p.mo.height/2, ang = R_PointToAngle2(p.mo.x, p.mo.y, target.x, target.y), zang = angletotarget, distance = 2048*FU, steps = 128, tclip = false, lclip = true, size = 2, ignore = p.mo}) then continue end
		if target.type == MT_PLAYER then
			if target.player.spectator then continue end
			if CanPlayerHurtPlayerTeam(p,target.player, 1) then //or RFW.assistff.value //we aren't local so we cant do this here
				if p.mo.aimassistdelay ~= 11 then
					p.mo.aimassistdelay = min($+2, 11)
				end
				if p.mo.aimassistdelay == 11 then
					p.mo.lockontarget = target
				end
				break
			else
				continue
			end
		elseif target.flags & (MF_ENEMY|MF_BOSS) then
			if RFW.assiststyle.value == 0 then
				p.mo.aimassistdelay = 11
				p.mo.lockontarget = target
				break
			else
				if p.mo.aimassistdelay ~= 11 then
					p.mo.aimassistdelay = min($+2, 11)
				end
				if p.mo.aimassistdelay == 11 then
					p.mo.lockontarget = target
				end
				break
			end
		else
			continue
		end
	end
end) */

//addHook("PlayerThink", function(p)
	//if p.aimassist == nil or p.aimassist == 0 then return end
	/*if p.mo.lockontarget ~= nil then
		if RFW.assiststyle.value == 0 then
			//if not netgame then //this is a patch fix right now, re-enable this code in netgames when angle multiplication no longer suffers from lag (use cmd instead of object angles)
			//	if p.mo.oldangle2 then
			//		p.mo.angle = RFW.MultiplyAngle(p, p.mo.oldangle2 or 0, FU/4, p.mo.angle)
			//	end
			//	if p.oldaiming2 then
			//		p.aiming = RFW.MultiplyAngle(p, p.oldaiming2 or 0, FU/4, p.aiming)
			//	end
			//end
			//p.mo.oldangle2 = p.mo.angle
			//p.oldaiming2 = p.aiming
			if p.mo.lockontargetoldmo ~= p.mo.lockontarget and p.mo.lockontargetoldmo ~= nil then
				p.mo.lockontargetoldx = nil
				p.mo.lockontargetoldy = nil
				p.mo.lockontargetoldz = nil
				p.mo.lockontargetoldmo = nil
				p.mo.oldx = nil
				p.mo.oldy = nil
				p.mo.oldz = nil
				p.mo.oldheight = nil
			else
				p.mo.angle = $ + (R_PointToAngle2(p.mo.x, p.mo.y, p.mo.lockontarget.x, p.mo.lockontarget.y) - R_PointToAngle2(p.mo.oldx or p.mo.x, p.mo.oldy or p.mo.y, p.mo.lockontargetoldx or p.mo.lockontarget.x, p.mo.lockontargetoldy or p.mo.lockontarget.y))
				local vector1 = R_PointToDist2(p.mo.x, p.mo.y, p.mo.lockontarget.x, p.mo.lockontarget.y)
				local vector2 = R_PointToDist2(p.mo.oldx or p.mo.x, p.mo.oldy or p.mo.y, p.mo.lockontargetoldx or p.mo.lockontarget.x, p.mo.lockontargetoldy or p.mo.lockontarget.y)
				p.aiming = $ + (R_PointToAngle2(0, p.mo.z+p.mo.height/2, vector1, p.mo.lockontarget.z+p.mo.lockontarget.height/2) - R_PointToAngle2(0, (p.mo.oldz or p.mo.z)+(p.mo.oldheight or p.mo.height)/2, vector2, (p.mo.lockontargetoldz or p.mo.lockontarget.z) + p.mo.lockontarget.height/2))
				p.mo.lockontargetoldx = p.mo.lockontarget.x
				p.mo.lockontargetoldy = p.mo.lockontarget.y
				p.mo.lockontargetoldz = p.mo.lockontarget.z
				p.mo.lockontargetoldmo = p.mo.lockontarget
				p.mo.oldx = p.mo.x
				p.mo.oldy = p.mo.y
				p.mo.oldz = p.mo.z
				p.mo.oldheight = p.mo.height
			end
		else
			if p.aimassist ~= 2 then
				p.mo.angle = R_PointToAngle2(p.mo.x, p.mo.y, p.mo.lockontarget.x, p.mo.lockontarget.y)
			end
			if p.aimassist ~= 3 then
				local vector = R_PointToDist2(p.mo.x, p.mo.y, p.mo.lockontarget.x, p.mo.lockontarget.y)
				p.aiming = R_PointToAngle2(0, p.mo.z+p.mo.height/2, vector, p.mo.lockontarget.z+p.mo.lockontarget.height/2)
			end
		end
	elseif RFW.assiststyle.value == 0 and p.mo.lockontarget == nil then
		p.mo.oldangle2 = nil
		p.oldaiming2 = nil
		p.mo.lockontargetoldx = nil
		p.mo.lockontargetoldy = nil
		p.mo.lockontargetoldz = nil
		p.mo.lockontargetoldmo = nil
		p.mo.oldx = nil
		p.mo.oldy = nil
		p.mo.oldz = nil
		p.mo.oldheight = nil
	end*/
//end)

local function ccw(Ax,Bx,Cx,Ay,By,Cy) //nabbed this from a python guide
    return FixedMul((Cy-Ay), (Bx-Ax)) > FixedMul((By-Ay), (Cx-Ax))
end

local function intersect(Ax,Bx,Cx,Dx,Ay,By,Cy,Dy)
    return ccw(Ax,Cx,Dx,Ay,Cy,Dy) != ccw(Bx,Cx,Dx,By,Cy,Dy) and ccw(Ax,Bx,Cx,Ay,By,Cy) != ccw(Ax,Bx,Dx,Ay,By,Dy)
end

local function DoubleXYLineCollide(x, y, ox, oy, mo, size)
	local flags = mo.flags
	if flags & (MF_NOCLIP|MF_NOCLIPTHING) then return false end
	if not (flags & MF_SHOOTABLE) then return false end
	local mx = mo.x
	local my = mo.y
	local rad = mo.radius * size
	local mA = mo.x - rad //x 1
	local mB = mo.x + rad //x 2
	local mC = mo.y + rad //y
	if x >= mx-rad and x <= mx+rad and y >= my-rad and y <= my+rad then return true end
	if intersect(ox,x,mA,mB,oy,y,mC,mC,true,true) then return true end
	local mC = mo.y - rad //new y
	if intersect(ox,x,mA,mB,oy,y,mC,mC,true,true) then return true end
	local mA = mo.y - rad //y 1
	local mB = mo.y + rad //y 2
	local mC = mo.x + rad //x
	if intersect(ox,x,mC,mC,oy,y,mA,mB,true,true) then return true end
	local mC = mo.x - rad //new x
	if intersect(ox,x,mC,mC,oy,y,mA,mB,true,true) then return true end
	return false
end

rawset(_G, "P_LocalMagnetizedXYRaycast", function(args)
	// Arguments
	local x = ParseArg(args, "x", 0)
	local y = ParseArg(args, "y", 0)
	local ang = ParseArg(args, "ang", 0)
	local distance = ParseArg(args, "distance", 2048*FU)
	local steps = ParseArg(args, "steps", 32)
	local size = ParseArg(args, "size") //multiplier, 2 will magnetize to twice the normal hitbox, 3 will magnetize to three times the normal hitbox, so on.
	local source = ParseArg(args, "source")

	local collisionlist = {}
	local collisionset = {}
	local vx = cos(ang)
	local vy = sin(ang)
	local ox
	local oy

	local move = distance/steps
	
	//local bruhhhh = 0

	for stepcount = 1, steps do
		ox = x
		oy = y
		x = $ + FixedMul(move, vx)
		y = $ + FixedMul(move, vy)

		if searchBlockmap("objects", function(ref, object)
			if object == source then return nil end
			if collisionset[object] then return nil end
			if DoubleXYLineCollide(x, y, ox, oy, object, size) == true then
				table.insert(collisionlist, {x, y, object})
				collisionset[object] = true
				if tclip == true or tclip == 1 then return true
				else return nil end
			end
		end, source, x-256*FU, x+256*FU, y-256*FU, y+256*FU) == false then break end
	
		if lclip == true or lclip == 1 then
			if R_PointInSubsectorOrNil(x, y) == nil then //check walls
				//bruhhhh = $ + 1
				break
			end
		end
	end
	return collisionlist
end)

local function DoubleLineCollide(x, y, z, ox, oy, mo, size)
	local flags = mo.flags
	if flags & (MF_NOCLIP|MF_NOCLIPTHING) then return false end
	if not (flags & MF_SHOOTABLE) then return false end
	local mx = mo.x
	local my = mo.y
	local rad = mo.radius*size
	local mA = mx - rad //x 1
	local mB = mx + rad //x 2
	local mC = my + rad //y
	local bruh = mo.z+mo.height
	if x >= mx-rad and x <= mx+rad and y >= my-rad and y <= my+rad then //if our coordinate is already in the hitbox we don't need to do math lmao
		local pos = mo.z
		local mheight = mo.height
		if z > mheight+pos+(mheight*(size-1)/2) then return false end
		if z < pos-(mheight*(size-1)/2) then return false end
		return true
	end
	if intersect(ox,x,mA,mB,oy,y,mC,mC,true,true) then
		local pos = mo.z
		local mheight = mo.height
		if z > mheight+pos+(mheight*(size-1)/2) then return false end
		if z < pos-(mheight*(size-1)/2) then return false end
		return true
	end
	local mC = my - rad //new y
	if intersect(ox,x,mA,mB,oy,y,mC,mC,true,true) then
		local pos = mo.z
		local mheight = mo.height
		if z > mheight+pos+(mheight*(size-1)/2) then return false end
		if z < pos-(mheight*(size-1)/2) then return false end
		return true
	end
	local mA = my - rad //y 1
	local mB = my + rad //y 2
	local mC = mx + rad //x
	if intersect(ox,x,mC,mC,oy,y,mA,mB,true,true) then
		local pos = mo.z
		local mheight = mo.height
		if z > mheight+pos+(mheight*(size-1)/2) then return false end
		if z < pos-(mheight*(size-1)/2) then return false end
		return true
	end
	local mC = mx - rad //new x
	if intersect(ox,x,mC,mC,oy,y,mA,mB,true,true) then
		local pos = mo.z
		local mheight = mo.height
		if z > mheight+pos+(mheight*(size-1)/2) then return false end
		if z < pos-(mheight*(size-1)/2) then return false end
		return true
	end
	return false
end

rawset(_G, "P_LocalMagnetizedAngleRaycast", function(args)
	// Arguments
	local x = ParseArg(args, "x", 0)
	local y = ParseArg(args, "y", 0)
	local z = ParseArg(args, "z", 0)
	local ang = ParseArg(args, "ang", 0)
	local zang = ParseArg(args, "zang", 0)
	local distance = ParseArg(args, "distance", 2048*FU)
	local steps = ParseArg(args, "steps", 32)
	local tclip = ParseArg(args, "tclip")
	local lclip = ParseArg(args, "lclip")
	local size = ParseArg(args, "size") //multiplier, 2 will magnetize to twice the normal hitbox, 3 will magnetize to three times the normal hitbox, so on.
	local source = ParseArg(args, "source")

	local collisionlist = {}
	local collisionset = {}
	local vx = FixedMul(cos(ang), cos(zang))
	local vy = FixedMul(sin(ang), cos(zang))
	local vz = sin(zang)
	local ox
	local oy
	local oz

	local move = distance/steps

	for stepcount = 1, steps do
		ox = x
		oy = y
		oz = z
		x = $ + FixedMul(move, vx)
		y = $ + FixedMul(move, vy)
		z = $ + FixedMul(move, vz)

		if searchBlockmap("objects", function(ref, object)
			//if object.type ~= MT_PLAYER then return nil end
			if object == ignore then return nil end
			if collisionset[object] then return nil end
			if DoubleLineCollide(x, y, z, ox, oy, object, size) == true then
				table.insert(collisionlist, {x, y, z, object})
				collisionset[object] = true
				if tclip == true or tclip == 1 then return true
				else return nil end
			end
		end, source, x-256*FU, x+256*FU, y-256*FU, y+256*FU) == false then break end //the xxyy values are a hacky fix for an issue too long to explain in a single line comment.
//, raycastMobj.x - 128*FU*(size-1), raycastMobj.x + 128*FU*(size-1), raycastMobj.y - 128*FU*(size-1), raycastMobj.y + 128*FU*(size-1)
		if lclip == true or lclip == 1 then
			local sect = R_PointInSubsector(x, y).sector
			local floorheight = sect.floorheight
			local ceilheight = sect.ceilingheight
			if sect.f_slope then
				local slope = sect.f_slope
				local vectorx = x-slope.o.x //distance from origin x
				local vectory = y-slope.o.y //distance from origin y
				local angle = slope.xydirection //horizontal angle of slope
				local dist = FixedMul(vectorx, cos(angle))+FixedMul(vectory, sin(angle)) //distance from origin
				local vectorz = FixedMul(tan(slope.zangle), dist) //the slope's distance from origin z at this specific part of the slope
				floorheight = vectorz + slope.o.z
			end
			if sect.c_slope then
				local slope = sect.c_slope
				local vectorx = x-slope.o.x //distance from origin x
				local vectory = y-slope.o.y //distance from origin y
				local angle = slope.xydirection //horizontal angle of slope
				local dist = FixedMul(vectorx, cos(angle))+FixedMul(vectory, sin(angle)) //distance from origin
				local vectorz = FixedMul(tan(slope.zangle), dist) //the slope's distance from origin z at this specific part of the slope
				ceilheight = vectorz + slope.o.z
			end
			if z < floorheight or z > ceilheight then //in floor or ceiling
				break
			end
			local shouldbreak = 0
			for fof in sect.ffloors() do
				if not (fof.flags & FOF_SOLID) then continue end
				if not (fof.flags & FOF_EXISTS) then continue end
				local topheight = fof.topheight
				local bottomheight = fof.bottomheight
				if fof.t_slope then
					local slope = fof.t_slope
					local vectorx = x-slope.o.x //distance from origin x
					local vectory = y-slope.o.y //distance from origin y
					local angle = slope.xydirection //horizontal angle of slope
					local dist = FixedMul(vectorx, cos(angle))+FixedMul(vectory, sin(angle)) //distance from origin
					local vectorz = FixedMul(tan(slope.zangle), dist) //the slope's distance from origin z at this specific part of the slope
					topheight = vectorz + slope.o.z
				end
				if fof.b_slope then
					local slope = fof.b_slope
					local vectorx = x-slope.o.x //distance from origin x
					local vectory = y-slope.o.y //distance from origin y
					local angle = slope.xydirection //horizontal angle of slope
					local dist = FixedMul(vectorx, cos(angle))+FixedMul(vectory, sin(angle)) //distance from origin
					local vectorz = FixedMul(tan(slope.zangle), dist) //the slope's distance from origin z at this specific part of the slope
					bottomheight = vectorz + slope.o.z
				end
				if (z <= topheight and z >= bottomheight) then
					shouldbreak = 1
					break
				end
			end
			if shouldbreak == 1 then
				break
			end
			if R_PointInSubsectorOrNil(x, y) == nil then
				break
			end
		end
	end
	return collisionlist
end)

local oldangle1 = 0
local oldangle2 = 0
local oldaim1 = 0
local oldaim2 = 0
local locktarget1 = nil
local locktarget2 = nil
local lockontargetoldx1 = nil
local lockontargetoldy1 = nil
local lockontargetoldz1 = nil
local lockontargetoldmo1 = nil
local oldx1 = nil
local oldy1 = nil
local oldz1 = nil
local oldheight1 = nil
local lockontargetoldx2 = nil
local lockontargetoldy2 = nil
local lockontargetoldz2 = nil
local lockontargetoldmo2 = nil
local oldx2 = nil
local oldy2 = nil
local oldz2 = nil
local oldheight2 = nil
local assistdelay1 = 0
local assistdelay2 = 0

addHook("PlayerCmd", function(p, cmd)
	//if p.aimassist == 0 then return end
	if p == consoleplayer then
		//local targetlist = P_LocalMagnetizedXYRaycast{x = p.mo.x, y = p.mo.y, ang = p.mo.angle, distance = 2048*FU, steps = 128, tclip = false, lclip = true, size = RFW.maxaimassist.value, source = p.mo}
		local targetlist = P_LocalMagnetizedAngleRaycast{x = p.mo.x, y = p.mo.y, z = p.mo.z + p.mo.height/2, ang = p.mo.angle, zang = p.aiming, distance = 2048*FU, steps = 128, tclip = false, lclip = true, size = RFW.maxaimassist.value, source = p.mo}
		locktarget1 = nil
		if not next(targetlist) then return end
		for i = 1, #targetlist do
			local target = targetlist[i][4]
			local angletotarget = R_PointToAngle2(0, p.mo.z+p.mo.height/2, R_PointToDist2(p.mo.x, p.mo.y, target.x, target.y), target.z+target.height/2)
			if abs(p.aiming-angletotarget) > ANG30 then continue end //dont cut from extreme angles
			//if not next(P_LocalMagnetizedAngleRaycast{x = p.mo.x, y = p.mo.y, z = p.mo.z + p.mo.height/2, ang = R_PointToAngle2(p.mo.x, p.mo.y, target.x, target.y), zang = angletotarget, distance = 2048*FU, steps = 128, tclip = false, lclip = true, size = 2, source = p.mo}) then continue end
			if target.type == MT_PLAYER then
				if target.player.spectator then continue end
				if CanPlayerHurtPlayerTeam(p,target.player, 1) or RFW.assistff.value then
					if RFW.assiststyle.value == 0 then
						assistdelay1 = 11
						locktarget1 = target
						break
					else
						if assistdelay1 ~= 11 then
							assistdelay1 = min($+2, 11)
						end
						if assistdelay1 == 11 then
							locktarget1 = target
						end
						break
					end
				else
					continue
				end
			elseif target.flags & (MF_ENEMY|MF_BOSS) then
				if RFW.assiststyle.value == 0 then
					assistdelay1 = 11
					locktarget1 = target
					break
				else
					if assistdelay1 ~= 11 then
						assistdelay1 = min($+2, 11)
					end
					if assistdelay1 == 11 then
						locktarget1 = target
					end
					break
				end
			else
				continue
			end
		end
	elseif p == secondarydisplayplayer then
		//local targetlist = P_LocalMagnetizedXYRaycast{x = p.mo.x, y = p.mo.y, ang = p.mo.angle, distance = 2048*FU, steps = 128, tclip = false, lclip = true, size = RFW.maxaimassist.value, source = p.mo}
		local targetlist = P_LocalMagnetizedAngleRaycast{x = p.mo.x, y = p.mo.y, z = p.mo.z + p.mo.height/2, ang = p.mo.angle, zang = p.aiming, distance = 2048*FU, steps = 128, tclip = false, lclip = true, size = RFW.maxaimassist.value, source = p.mo}
		locktarget2 = nil
		if not next(targetlist) then return end
		for i = 1, #targetlist do
			local target = targetlist[i][4]
			local angletotarget = R_PointToAngle2(0, p.mo.z+p.mo.height/2, R_PointToDist2(p.mo.x, p.mo.y, target.x, target.y), target.z+target.height/2)
			if abs(p.aiming-angletotarget) > ANG30 then continue end //dont cut from extreme angles
			//if not next(P_LocalMagnetizedAngleRaycast{x = p.mo.x, y = p.mo.y, z = p.mo.z + p.mo.height/2, ang = R_PointToAngle2(p.mo.x, p.mo.y, target.x, target.y), zang = angletotarget, distance = 2048*FU, steps = 128, tclip = false, lclip = true, size = 2, source = p.mo}) then continue end
			if target.type == MT_PLAYER then
				if target.player.spectator then continue end
				if CanPlayerHurtPlayerTeam(p,target.player, 1) or RFW.assistff.value then
					if RFW.assiststyle.value == 0 then
						assistdelay2 = 11
						locktarget2 = target
						break
					else
						if assistdelay2 ~= 11 then
							assistdelay2 = min($+2, 11)
						end
						if assistdelay2 == 11 then
							locktarget2 = target
						end
						break
					end
				else
					continue
				end
			elseif target.flags & (MF_ENEMY|MF_BOSS) then
				if RFW.assiststyle.value == 0 then
					assistdelay2 = 11
					locktarget2 = target
					break
				else
					if assistdelay2 ~= 11 then
						assistdelay2 = min($+2, 11)
					end
					if assistdelay2 == 11 then
						locktarget2 = target
					end
					break
				end
			else
				continue
			end
		end
	end
end)

local function LerpAngleTurn() //since multiply angle was having jittering problems

end

addHook("PlayerCmd", function(p, cmd)
	//print(locktarget1)
	if p.aimassist == nil or p.aimassist == 0 then return end
	if p == consoleplayer then
		if locktarget1 ~= nil then
			if RFW.assiststyle.value == 0 then
				if oldangle1 ~= nil then
					cmd.angleturn = RFW.MultiplyAngle(p, oldangle1<<16, FU/4, cmd.angleturn<<16)>>16
				end
				if oldaim1 ~= nil then
					cmd.aiming = RFW.MultiplyAngle(p, oldaim1<<16, FU/4, cmd.aiming<<16)>>16
				end
				if lockontargetoldmo1 ~= locktarget1 and lockontargetoldmo1 ~= nil then
					lockontargetoldx1 = nil
					lockontargetoldy1 = nil
					lockontargetoldz1 = nil
					lockontargetoldmo1 = nil
					oldx1 = nil
					oldy1 = nil
					oldz1 = nil
					oldheight1 = nil
					return
				else
					cmd.angleturn = $ + (R_PointToAngle2(p.mo.x, p.mo.y, locktarget1.x, locktarget1.y) - R_PointToAngle2(oldx1 or p.mo.x, oldy1 or p.mo.y, lockontargetoldx1 or locktarget1.x, lockontargetoldy1 or locktarget1.y))>>16
					local vector1 = R_PointToDist2(p.mo.x, p.mo.y, locktarget1.x, locktarget1.y)
					local vector2 = R_PointToDist2(oldx1 or p.mo.x, oldy1 or p.mo.y, lockontargetoldx1 or locktarget1.x, lockontargetoldy1 or locktarget1.y)
					cmd.aiming = $ + (R_PointToAngle2(0, p.mo.z+p.mo.height/2, vector1, locktarget1.z+locktarget1.height/2) - R_PointToAngle2(0, (oldz1 or p.mo.z)+(oldheight1 or p.mo.height)/2, vector2, (lockontargetoldz1 or locktarget1.z) + locktarget1.height/2))>>16
					lockontargetoldx1 = locktarget1.x
					lockontargetoldy1 = locktarget1.y
					lockontargetoldz1 = locktarget1.z
					lockontargetoldmo1 = locktarget1
					oldx1 = p.mo.x
					oldy1 = p.mo.y
					oldz1 = p.mo.z
					oldheight1 = p.mo.height
				end
			else
				if p.aimassist ~= 2 then
					cmd.angleturn = R_PointToAngle2(p.mo.x, p.mo.y, locktarget1.x, locktarget1.y)>>16
				end
				if p.aimassist ~= 3 then
					local vector = R_PointToDist2(p.mo.x, p.mo.y, locktarget1.x, locktarget1.y)
					cmd.aiming = R_PointToAngle2(0, p.mo.z+p.mo.height/2, vector, locktarget1.z+locktarget1.height/2)>>16
				end
			end
			//print("fart")
		elseif RFW.assiststyle.value == 0 and p.mo.lockontarget == nil then
			//p.mo.oldangle2 = nil
			//p.oldaiming2 = nil
			lockontargetoldx1 = nil
			lockontargetoldy1 = nil
			lockontargetoldz1 = nil
			lockontargetoldmo1 = nil
			oldx1 = nil
			oldy1 = nil
			oldz1 = nil
			oldheight1 = nil
		end
		oldangle1 = cmd.angleturn
		oldaim1 = cmd.aiming
	elseif p == secondarydisplayplayer then
		if locktarget2 ~= nil then
			if RFW.assiststyle.value == 0 then
				if oldangle2 then
					cmd.angleturn = RFW.MultiplyAngle(p, oldangle2<<16, FU/4, cmd.angleturn<<16)>>16
				end
				if oldaim2 then
					cmd.aiming = RFW.MultiplyAngle(p, oldaim2<<16, FU/4, cmd.aiming<<16)>>16
				end
				if lockontargetoldmo2 ~= locktarget2 and lockontargetoldmo2 ~= nil  then
					lockontargetoldx2 = nil
					lockontargetoldy2 = nil
					lockontargetoldz2 = nil
					lockontargetoldmo2 = nil
					oldx2 = nil
					oldy2 = nil
					oldz2 = nil
					oldheight2 = nil
				else
					cmd.angleturn = $ + (R_PointToAngle2(p.mo.x, p.mo.y, locktarget2.x, locktarget2.y) - R_PointToAngle2(oldx2 or p.mo.x, oldy2 or p.mo.y, lockontargetoldx2 or locktarget2.x, lockontargetoldy2 or locktarget2.y))>>16
					local vector1 = R_PointToDist2(p.mo.x, p.mo.y, locktarget2.x, locktarget2.y)
					local vector2 = R_PointToDist2(oldx2 or p.mo.x, oldy2 or p.mo.y, lockontargetoldx2 or locktarget2.x, lockontargetoldy2 or locktarget2.y)
					cmd.aiming = $ + (R_PointToAngle2(0, p.mo.z+p.mo.height/2, vector1, locktarget2.z+locktarget2.height/2) - R_PointToAngle2(0, (oldz2 or p.mo.z)+(oldheight2 or p.mo.height)/2, vector2, (lockontargetoldz2 or locktarget2.z) + locktarget2.height/2))>>16
					lockontargetoldx2 = locktarget2.x
					lockontargetoldy2 = locktarget2.y
					lockontargetoldz2 = locktarget2.z
					lockontargetoldmo2 = locktarget2
					oldx2 = p.mo.x
					oldy2 = p.mo.y
					oldz2 = p.mo.z
					oldheight2 = p.mo.height
				end
			else
				if p.aimassist ~= 2 then
					cmd.angleturn = R_PointToAngle2(p.mo.x, p.mo.y, locktarget2.x, locktarget2.y)>>16
				end
				if p.aimassist ~= 3 then
					local vector = R_PointToDist2(p.mo.x, p.mo.y, locktarget2.x, locktarget2.y)
					cmd.aiming = R_PointToAngle2(0, p.mo.z+p.mo.height/2, vector, locktarget2.z+locktarget2.height/2)>>16
				end
			end
		elseif RFW.assiststyle.value == 0 and p.mo.lockontarget == nil then
			//p.mo.oldangle2 = nil
			//p.oldaiming2 = nil
			lockontargetoldx2 = nil
			lockontargetoldy2 = nil
			lockontargetoldz2 = nil
			lockontargetoldmo2 = nil
			oldx2 = nil
			oldy2 = nil
			oldz2 = nil
			oldheight2 = nil
		end
		oldangle2 = cmd.angleturn
		oldaim2 = cmd.aiming
	end
end)

local autofiredelay1 = 0
local autofiredelay2 = 0

/*addHook("PlayerThink", function(p)
	if not (p.mo and p.mo.valid) then return end
	if not p.autofire then 
		p.mo.autofiredelay = 0
		return 
	end
	if p.mo.autofiredelay == nil then
		p.mo.autofiredelay = 0
	end
	local targetlist = P_MagnetizedAngleRaycast{x = p.mo.x, y = p.mo.y, z = p.mo.z + p.mo.height/2, ang = p.mo.angle, zang = p.aiming, distance = 2048*FU, steps = 128, tclip = false, lclip = true, size = 2, ignore = p.mo}
	if p.mo.lockontarget and next(targetlist) and p.mo.autofiredelay ~= 11 then
		p.mo.autofiredelay = min($+1, 11)
	elseif ((not p.mo.lockontarget) or (not next(targetlist))) and p.mo.autofiredelay ~= 0 then
		p.mo.autofiredelay = max($-1, 0)
	end
end)*/

addHook("PlayerCmd", function(p, cmd)
	if not (p.mo and p.mo.valid) then return end
	if p == consoleplayer then
		if not p.autofire then 
			autofiredelay1 = 0
			return 
		end
		if autofiredelay1 == nil then
			autofiredelay1 = 0
		end
		local targetlist = P_LocalMagnetizedAngleRaycast{x = p.mo.x, y = p.mo.y, z = p.mo.z + p.mo.height/2, ang = p.mo.angle, zang = p.aiming, distance = 2048*FU, steps = 128, tclip = false, lclip = true, size = 2, source = p.mo}
		if locktarget1 and next(targetlist) and autofiredelay1 ~= 11 then
			autofiredelay1 = min($+1, 11)
		elseif ((not locktarget1) or (not next(targetlist))) and autofiredelay1 ~= 0 then
			autofiredelay1 = max($-1, 0)
		end
		if autofiredelay1 == 11 then
			cmd.buttons = $ | BT_ATTACK
		end
	elseif p == secondarydisplayplayer then
		if not p.autofire then 
			autofiredelay2 = 0
			return 
		end
		if autofiredelay2 == nil then
			autofiredelay2 = 0
		end
		local targetlist = P_LocalMagnetizedAngleRaycast{x = p.mo.x, y = p.mo.y, z = p.mo.z + p.mo.height/2, ang = p.mo.angle, zang = p.aiming, distance = 2048*FU, steps = 128, tclip = false, lclip = true, size = 2, source = p.mo}
		if locktarget2 and next(targetlist) and autofiredelay2 ~= 11 then
			autofiredelay2 = min($+1, 11)
		elseif ((not locktarget2) or (not next(targetlist))) and autofiredelay2 ~= 0 then
			autofiredelay2 = max($-1, 0)
		end
		if autofiredelay2 == 11 then
			cmd.buttons = $ | BT_ATTACK
		end
	end
end)

//S_StartSound(s, sfx_hitsnd, s.player)
hud.add(function(v, p)
	//if not (splitscreen) and displayplayer.aimassist == nil or displayplayer.aimassist == 0 then return end
	local bcenterx = 160 - ((v.width()/(v.dupx() * 2) - 160))
	local bcentery = 100 + ((v.height()/(v.dupy() * 2) - 100))
	if p.aimassist ~= nil and p.aimassist ~= 0 then //my fat braindead playtesters lied and said the aimassist notification only rendered for them bruh, JUST TESTED IT AND IT RENDERS
		//if splitscreen and p.aimassist == nil or p.aimassist == 0 then return end
		//if RFW.assiststyle.value ~= 0 then
		//	if p.mo.aimassistdelay and p.mo.aimassistdelay < 11 then
		//		if not S_SoundPlaying(p.mo, sfx_locko1) then
		//			S_StartSound(p.mo, sfx_locko1, p)
		//		end
		//	end
		//	v.drawFill(160-5, 92, p.mo.aimassistdelay, 1, 152|V_70TRANS|V_PERPLAYER)
		//end
		v.drawString(bcenterx, bcentery + 4, "Aim Assist is enabled!", V_ALLOWLOWERCASE|V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_PERPLAYER|V_REDMAP|V_HUDTRANSHALF, "small-center")
		//v.drawString(bcenterx, bcentery + 8, "(" .. p.aimassist .. ")", V_ALLOWLOWERCASE|V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_PERPLAYER|colormap|V_HUDTRANSHALF, "small-center")
	end
	if p.autofire then
		//if p.mo.autofiredelay and p.mo.autofiredelay < 11 then
		//	if not S_SoundPlaying(p.mo, sfx_autof1) then
		//		S_StartSound(p.mo, sfx_autof1, p)
		//	end
		//end
		v.drawString(bcenterx, bcentery + 8, "Autofire is enabled!", V_ALLOWLOWERCASE|V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_PERPLAYER|V_YELLOWMAP|V_HUDTRANSHALF, "small-center")
		//v.drawFill(160-5, 108, p.mo.autofiredelay, 1, 72|V_70TRANS|V_PERPLAYER)
	end
end, "game")
